<script>
import { uuid } from '@/utils'
import { selectEnergyDiscountList } from '@/api/energyDiscount'
import {
  loadCompanyProduct,
  loadCompanyIndicatorDetails,
  loadEnergyConsumptionStructure,
  loadEnergyConsumptionStructureSchedule,
  loadEquipmentStatus,
  loadGoalCompletionStatus,
  loadReconstructionProject,
  loadProductEnergyConsumption,
} from '@/api/enterpriseQuarterlyReport'
import { loadDescription } from '@/api/descriptionManagement'
import {
  PROGRESS_ENERGY_SAVING_TARGET_COMPLETION_TABLE,
  TABLE_OF_COMPREHENSIVE_ENERGY_CONSUMPTION_PER_UNIT_PRODUCT,
  CONDITION_TABLE_OF_MAJOR_ENERGY_CONSUMING_EQUIPMENT,
  ENERGY_SAVING_RENOVATION_PROJECT_INFORMATION_TABLE,
  ENERGY_CONSUMPTION_STRUCTURE_TABLE,
  ENERGY_CONSUMPTION_STRUCTURE_SUB_TABLE,
  COMPANY_PRODUCT_LIST,
  DETAILED_LIST_OF_COMPANY_INDICATORS,

  TABLE_FIELD_YEAR,
  TABLE_FIELD_QUARTER,
} from '@/config'
import TableHead from '@/components/quarterly-account-table/table-head.vue'
import ReportPerson from '@/components/quarterly-account-table/report-person.vue'

// 行选中状态的CSS类
const SELECTED_CLASS = 'is-selected'

export default {
  name: 'quarterly-account-table',
  components: { TableHead, ReportPerson },
  props: {
    // 企业ID
    enterpriseId: {
      type: String,
      required: true,
    },
    // 企业名称
    enterpriseName: String,
    // 年份
    year: {
      type: [String, Number],
      required: true,
    },
    // 季度
    quarter: {
      type: [String, Number],
      required: true,
    },
    // 表ID
    tId: {
      type: Number,
      required: true,
    },
    // 表名称
    name: {
      type: String,
      required: true,
    },
    // 表数据项
    columns: {
      type: Array,
      required: true,
    },
    // 政府端
    isGovernment: Boolean,
    readonly: Boolean,
    showLineNumber: {
      type: Boolean,
      default: true,
    }
  },
  data () {
    return {
      // 点击单元格后，正在输入的input索引
      inputIndex: -1,

      // 选中tbody里某一行tr的索引
      rowIndex: -1,

      // 右键后弹框
      visible: false,
      left: 0,
      top: 0,

      /**
       * 报表数据格式
       * [{uuid: string, data: string[]}]
       */
      lists: [],

      // 填报说明
      tableDescription: '',
    }
  },
  computed: {
    title () {
      // 年度
      if (Number(this.quarter) === 5) {
        return `${this.enterpriseName || ''}（${this.year}年）${this.name}`
      }
      if (this.enterpriseName) {
        return `${this.enterpriseName}（${this.year}年第${this.quarter}季度）${this.name}`
      }
      return `${this.name}（${this.year}年第${this.quarter}季度）`
    },
    fromGovernmentSide () {
      return this.isGovernment && this.readonly === true
    },
    loadList () {
      const tId = this.tId
      let method = null
      switch (tId) {
        case PROGRESS_ENERGY_SAVING_TARGET_COMPLETION_TABLE.ID:
          method = loadGoalCompletionStatus
          break
        case TABLE_OF_COMPREHENSIVE_ENERGY_CONSUMPTION_PER_UNIT_PRODUCT.ID:
          method = loadProductEnergyConsumption
          break
        case CONDITION_TABLE_OF_MAJOR_ENERGY_CONSUMING_EQUIPMENT.ID:
          method = loadEquipmentStatus
          break
        case ENERGY_SAVING_RENOVATION_PROJECT_INFORMATION_TABLE.ID:
          method = loadReconstructionProject
          break
        case ENERGY_CONSUMPTION_STRUCTURE_TABLE.ID:
          method = loadEnergyConsumptionStructure
          break
        case COMPANY_PRODUCT_LIST.ID:
          method = loadCompanyProduct
          break
        case DETAILED_LIST_OF_COMPANY_INDICATORS.ID:
          method = loadCompanyIndicatorDetails
          break
        case ENERGY_CONSUMPTION_STRUCTURE_SUB_TABLE.ID:
          method = loadEnergyConsumptionStructureSchedule
          break
      }
      return method
    },

    // 多级表头转一级表头
    flattenColumns () {
      const columns = this.columns
      const getItems = (arr) => {
        const result = [];
        (function callback (arr) {
          for (let i = 0; i < arr.length; i++) {
            const { children, ...rest } = arr[i]
            if (children && children.length > 0) {
              callback(children)
            } else {
              result.push({ ...rest })
            }
          }
        })(arr)
        return result
      }
      return getItems(columns)
    },
    isProgressEnergySavingTargetCompletionTable () {
      return Number(this.tId) === PROGRESS_ENERGY_SAVING_TARGET_COMPLETION_TABLE.ID
    },
    isTableOfComprehensiveEnergyConsumptionPerUnitProduct () {
      return Number(this.tId) === TABLE_OF_COMPREHENSIVE_ENERGY_CONSUMPTION_PER_UNIT_PRODUCT.ID
    },
    isConditionTableOfMajorEnergyConsumingEquipment () {
      return Number(this.tId) === CONDITION_TABLE_OF_MAJOR_ENERGY_CONSUMING_EQUIPMENT.ID
    },
    isEnergySavingRenovationProjectInformationTable () {
      return Number(this.tId) === ENERGY_SAVING_RENOVATION_PROJECT_INFORMATION_TABLE.ID
    },
    isEnergyConsumptionStructureTable () {
      return Number(this.tId) === ENERGY_CONSUMPTION_STRUCTURE_TABLE.ID
    },
    isEnergyConsumptionStructureSubTable () {
      return Number(this.tId) === ENERGY_CONSUMPTION_STRUCTURE_SUB_TABLE.ID
    },
    isCompanyProductList () {
      return Number(this.tId) === COMPANY_PRODUCT_LIST.ID
    },
    isDetailedListOfCompanyIndicators () {
      return Number(this.tId) === DETAILED_LIST_OF_COMPANY_INDICATORS.ID
    },
    height () {
      if (this.isCompanyProductList) {
        return '130px'
      } else if (this.isEnergyConsumptionStructureTable) {
        return '146px'
      } else if (this.isEnergyConsumptionStructureSubTable) {
        return '124px'
      } else if (this.isTableOfComprehensiveEnergyConsumptionPerUnitProduct) {
        return '130px'
      } else if (this.isProgressEnergySavingTargetCompletionTable) {
        return '364px'
      } else if (this.isEnergySavingRenovationProjectInformationTable) {
        return '338px'
      }
      return '130px'
    },

    // 填报人相关信息
    informant () {
      const lists = this.lists
      const item = lists[0] && lists[0].informant
      if (!item) {
        return {}
      }
      return {
        principal: item.personInCharge || '',
        informant: item.informer || '',
        telephone: item.telephone || '',
        date: item.fillInDate || '',
      }
    },
  },
  watch: {
    tId (val) {
      this.getDescription(+val)
    }
  },
  beforeDestroy () {
    this.unbindArrowKeyEvent()
  },
  mounted () {
    this.getDescription(this.tId)
    this.initLists()
    this.bindArrowKeyEvent()
  },
  methods: {
    getEnergyDiscount () {
      return selectEnergyDiscountList().then(res => {
        return res.data || []
      })
    },
    getPrevLists (params) {
      return this.initLists(params)
    },
    refresh () {
      this.initLists()
    },
    _initLists (l, min) {
      min = min || 2
      if (l < min) {
        const columns = this.flattenColumns
        const rest = Array(min - l).fill(1).map(v => ({
          uuid: uuid(),
          data: Array(columns.length).fill('')
        }))
        this.lists = this.lists.concat(rest)
      }
    },
    // 初始化表数据
    initLists (params) {
      const props = this.flattenColumns.map(v => v.prop)

      const transfer = (obj) => {
        return props.map(prop => String(obj[prop] || ''))
      }
      // 查询企业填报的数据
      if (this.loadList) {
        params = params || {
          [TABLE_FIELD_YEAR]: this.year,
          [TABLE_FIELD_QUARTER]: this.quarter,
          tenantId: this.enterpriseId
        }
        return this.loadList(params).then(async res => {
          if (res.code === 200) {
            const data = res.data || []
            const setInformant = (v = {}) => ({
              personInCharge: v.personInCharge,
              informer: v.informer,
              telephone: v.telephone,
              fillInDate: v.fillInDate,
            })
            if (data.length === 0 && (this.isEnergyConsumptionStructureTable || this.isEnergyConsumptionStructureSubTable)) {
              // 为空时加载默认能源名称
              const energyDiscount = await this.getEnergyDiscount()
              this.lists = energyDiscount.map((v) => ({
                uuid: uuid(),
                data: transfer({
                  energyName: v.name || '',
                  unitOfMeasurement: v.discountFactorUnit ? (v.discountFactorUnit.split('/')[1]) : '吨标准煤',
                  referenceDiscountFactor: v.referenceCoefficient || '',
                  code: String(v.id).padStart(2, '0'),
                })
              }))
            } else {
              this.lists = data.map((v) => ({
                uuid: uuid(),
                data: transfer(v),
                informant: setInformant(v)
              }))
            }
            if (!this.fromGovernmentSide) {
              // 补足企业端不足40行的数据
              const l = this.lists.length
              this._initLists(l)
            }

            this.$nextTick(() => {
              this.initInputIndex()
            })
          }
        }).catch(() => {
          this._initLists(0)
          this.$nextTick(() => {
            this.initInputIndex()
          })
        })
      }
    },

    // 暴露给使用者的获取填报人相关信息
    getInformer () {
      return this.$refs.reportPerson && this.$refs.reportPerson.getData()
    },
    // 暴露给使用者的获取报表数据的方法
    // @return [{prop1: string, prop2: string, ...}]
    getData () {
      const props = this.flattenColumns.map(v => v.prop)
      const isNotEmpty = (array) => array.some(v => v !== '')

      // 二维数组 [string[], string[], ...]
      const lists = this.lists.map(v => v.data).filter(v => isNotEmpty(v))
      return lists.map(v => {
        const obj = {}
        props.forEach((prop, index) => {
          obj[prop] = v[index]
        })
        obj[TABLE_FIELD_YEAR] = String(this.year)
        obj[TABLE_FIELD_QUARTER] = String(this.quarter)
        return obj
      })
    },

    // 给每个input添加索引
    initInputIndex () {
      const inputs = document.querySelectorAll('.input-cell input')
      inputs.forEach((input, index) => {
        input.dataset.inputIndex = index + ''
      })
    },

    // 单击单元格（input框）
    clickHandler (evt, index) {
      evt.target.select()
      this.inputIndex = Number(evt.target.dataset.inputIndex)

      this.cancelRowSelected()

      if (index !== undefined) {
        this.rowIndex = index
      }
    },
    eventHandler (e) {
      const { key, keyCode } = e
      if (keyCode < 37 || keyCode > 40 || key.indexOf('Arrow') === -1) {
        return false
      }
      const inputs = document.querySelectorAll('.input-cell input')
      let inputIndex = this.inputIndex
      const length = this.flattenColumns.length
      // ArrowUp
      if (key === 'ArrowUp' || keyCode === 38) {
        inputIndex -= length
      }
      // ArrowDown
      if (key === 'ArrowDown' || keyCode === 40) {
        inputIndex += length
      }
      // ArrowLeft
      if (key === 'ArrowLeft' || keyCode === 37) {
        inputIndex--
      }
      // ArrowRight
      if (key === 'ArrowRight' || keyCode === 39) {
        inputIndex++
      }
      if (inputIndex >= 0 && inputIndex <= inputs.length - 1) {
        this.inputIndex = inputIndex
      }
      inputs[this.inputIndex] && inputs[this.inputIndex].click()
      inputs[this.inputIndex] && inputs[this.inputIndex].scrollIntoView(false)
    },

    // 绑定方向快捷键事件
    bindArrowKeyEvent () {
      document.addEventListener('keyup', this.eventHandler, false)
    },

    // 解除绑定方向快捷键事件
    unbindArrowKeyEvent () {
      document.removeEventListener('keyup', this.eventHandler, false)
    },

    // 更新 rowIndex
    updateRowIndex (tr) {
      const tbody = this.$refs.tbody
      const trs = Array.from(tbody.querySelectorAll('tr'))
      this.rowIndex = trs.findIndex(v => v === tr)
    },

    // 获取 trs
    getTrs () {
      const tbody = this.$refs.tbody
      return tbody ? Array.from(tbody.querySelectorAll('tr')) : []
    },
    // 单击行号
    clickLineNumber (evt) {
      evt.preventDefault()

      // 先关闭右键菜单弹框
      this.visible = false

      const target = evt.target
      const tr = target.parentNode

      this.selectRow(tr)
    },

    // 创建一空行
    createAEmptyRow () {
      const columns = this.flattenColumns
      return Array(columns.length).fill('')
    },

    /**
     * 选中指定行，同时更新 rowIndex
     * @param tr{HTMLTableRowElement}
     */
    selectRow (tr) {
      this.cancelRowSelected()
      tr && tr.classList.add(SELECTED_CLASS)

      // 更新 rowIndex
      this.updateRowIndex(tr)
    },

    // 取消行选中状态
    cancelRowSelected () {
      this.rowIndex = -1

      const trs = this.getTrs()
      trs.forEach(tr => {
        tr.classList.remove(SELECTED_CLASS)
      })

      // 没有选中的行 右键菜单弹框也应该关闭
      this.visible = false
    },

    // 选中某一行的情况下右键操作
    onContextmenu (evt) {
      if (this.readonly) return false

      let tr = evt.target
      while (tr) {
        if ((tr.tagName || '').toUpperCase() === 'TR') {
          break
        }
        tr = tr.parentNode
      }
      if (tr) {
        const menuMinWidth = 105
        const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
        const offsetWidth = this.$el.offsetWidth // container width
        const maxLeft = offsetWidth - menuMinWidth // left boundary
        const left = evt.clientX - offsetLeft + 15 // 15: margin right

        if (left > maxLeft) {
          this.left = maxLeft
        } else {
          this.left = left
        }

        this.top = evt.clientY - 100
        this.visible = true
      }
    },

    // 删除 rowIndex 行
    delRow () {
      const rowIndex = this.rowIndex
      this.$confirm('确定要删除这一行？').then(() => {
        this.lists.splice(rowIndex, 1)

        this.$nextTick(() => {
          const trs = this.getTrs()
          if (trs.length > 0) {
            if (rowIndex < trs.length) {
              this.selectRow(trs[rowIndex])
            } else {
              this.selectRow(trs[rowIndex - 1])
            }
          }
        })
        this.visible = false
      }).catch(() => {})
    },

    // 在 rowIndex 行前添加一行
    prependRow () {
      const rowIndex = this.rowIndex
      const emptyRow = this.createAEmptyRow()
      if (rowIndex > -1) {
        this.lists.splice(rowIndex, 0, {
          uuid: uuid(),
          data: [...emptyRow]
        })

        this.$nextTick(() => {
          const trs = this.getTrs()
          this.selectRow(trs[rowIndex])
        })
      }
      this.visible = false
    },

    // 在 rowIndex 行后添加一行
    appendRow () {
      const rowIndex = this.rowIndex
      const emptyRow = this.createAEmptyRow()
      if (rowIndex > -1) {
        this.lists.splice(rowIndex + 1, 0, {
          uuid: uuid(),
          data: [...emptyRow]
        })

        this.$nextTick(() => {
          const trs = this.getTrs()
          this.selectRow(trs[rowIndex + 1])
        })
      }
      this.visible = false
    },

    // 获取填报说明
    async getDescription (tId) {
      const { data } = await loadDescription(tId)
      const { descriptionContent } = data || {}
      this.tableDescription = descriptionContent || ''
    }
  },
}
</script>

<template>
  <div class="bg-white height-100 quarterly-account-table position-relative overflow-hidden">
    <slot name="title" :title="title">
      <h2 class="table-title">
        {{title}}
      </h2>
    </slot>
    <div class="report-table-head">
      <table class="report-table">
        <table-head :columns="columns" :show-line-number="showLineNumber"></table-head>
      </table>
    </div>
    <el-scrollbar :style="{height: 'calc(100% - ' + height + ')'}" wrap-style="overflow-x: hidden;">
      <table class="report-table">
        <tbody ref="tbody">
          <tr v-for="(item, i) in lists" :key="item.uuid" @contextmenu.prevent="onContextmenu">
            <th v-if="showLineNumber" class="readonly width-40px line-number" @click="clickLineNumber">{{i + 1}}</th>
            <td v-for="(value, index) in item.data" :key="item.uuid + index">
              <div class="input-cell" :class="{'is-readonly': readonly}">
                <input type="text" :readonly="readonly" v-model="item.data[index]" @click="clickHandler($event, i)">
              </div>
            </td>
          </tr>
        </tbody>
      </table>
      <report-person ref="reportPerson" :informer="informant"></report-person>
      <div v-if="tableDescription" class="fill-description">
        <el-input type="textarea" class="width-100 table-description" :value="tableDescription" readonly autosize></el-input>
      </div>
    </el-scrollbar>
    <transition name="el-fade-in">
      <ul v-if="visible" :style="{left:left+'px', top: top + 'px'}" class="contextmenu">
        <li style="color:var(--danger-color);" @click="delRow">删除当前行</li>
        <li class="divider"></li>
        <li @click="prependRow">在上方插入一行</li>
        <li @click="appendRow">在下方插入一行</li>
      </ul>
    </transition>
  </div>
</template>
